using System;
using System.Threading;
using Mono.Unix.Native;
using System.IO;

namespace Mehat.San.SanFS
{
	/*
	 * The GenericFile class handles all low level file operations on generic files. 
	 */
	public class GenericFile : DirectoryEntry, IFile
	{
		private Mutex			mLock = new Mutex();
		private IVirtualMount	mVMount = null;
		private Guid			mUuid = Guid.Empty;
		
		public GenericFile(ulong Inode, string Path, IDirectory Parent, Stat Stat, IVirtualMount VMount, Guid Uuid)
		: base(Inode, Path, Parent, Stat)
		{
			mVMount = VMount;
			mUuid = Uuid;
		}
		
		public void Open(FileHandle Handle)
		{
			if (Handle.State != EFileHandleState.Disconnected)
				throw new FileHandleAlreadyConnectedException(Handle);
			if ((Handle.ExternalFd = Syscall.open(((DirectoryEntry) Handle.File).ExternalPath, Handle.OpenInfo.OpenFlags)) < 0)
				throw new Exception("open failed");
		}
		
		public void Release(FileHandle Handle)
		{
			if (Handle.State != EFileHandleState.Connected)
				throw new FileHandleNotConnectedException(Handle);
			Syscall.close(Handle.ExternalFd);
		}
		
		public unsafe long Read(FileHandle Handle, byte[] Buffer, long Offset)
		{
			if (Handle.State != EFileHandleState.Connected)
				throw new FileHandleNotConnectedException(Handle);
			
			fixed (byte *bp = Buffer)
			{
				return Syscall.pread(Handle.ExternalFd, bp, (ulong) Buffer.Length, Offset);
			}
		}
		
		public void Flush(FileHandle Handle)
		{
			if (Handle.State != EFileHandleState.Connected)
				throw new FileHandleNotConnectedException(Handle);
			
			Syscall.fsync(Handle.ExternalFd);
		}
		
		public IVirtualMount VMount
		{
			get { return mVMount; }
		}
		
		public Mutex Lock
		{
			get { return mLock; }
		}
		
		public Guid Uuid
		{
			get { return mUuid; }
		}
	}  // END CLASS
}  // END NAMESPACE
